/****************************************************
	文件：GOLoader.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2020/10/10 15:44:39
	功能：GameObject 加载器（加载不需要大量生成的 GameObject）
*****************************************************/

using System;
using System.Collections.Generic;
using UnityEngine;
using HTUtility;

namespace HTFramework.ResKit
{
    public class GOLoader : Singleton<GOLoader>
    {
        /// <summary>
        /// GoItem 缓存
        /// </summary>
        private Dictionary<string, GoItem> mGoItemCache;
        /// <summary>
        /// GameObject 缓存
        /// </summary>
        private Dictionary<GameObject, GoItem> mGoCache;
        /// <summary>
        /// GoItem 类对象池
        /// </summary>
        private ClassObjectPool<GoItem> mGoItemPool;
        /// <summary>
        /// 回收节点
        /// </summary>
        public Transform RecycleTrans { get; private set; }
        /// <summary>
        /// 场景节点
        /// </summary>
        public Transform SceneTrans { get; private set; }

        public void Init(Transform recycleTrans, Transform sceneTrans)
        {
            mGoItemCache = new Dictionary<string, GoItem>(50);
            mGoCache = new Dictionary<GameObject, GoItem>(50);
            mGoItemPool = ClassPoolMgr.Instance.GetOrCreateObjectPool<GoItem>(50);
            RecycleTrans = recycleTrans;
            SceneTrans = sceneTrans;
            HTLogger.Info("GOLoader init done.");
        }

        /// <summary>
        /// 同步加载 GameObject
        /// </summary>
        /// <param name="path">加载路径</param>
        /// <returns></returns>
        public GameObject LoadSync(string path)
        {
            GoItem goItem = null;
            if (mGoItemCache.TryGetValue(path, out goItem))
            {
                if (System.Object.ReferenceEquals(goItem.Obj, null))
                {
                    HTLogger.Debug("同步加载 GameObject，Path：{0}", goItem.Path);
                    goItem.Obj = ResLoader.Instance.LoadSync<GameObject>(path);
                    goItem.GO = GameObject.Instantiate(goItem.Obj);
                }
                else
                {
                    if (System.Object.ReferenceEquals(goItem.GO, null))
                    {
                        goItem.GO = GameObject.Instantiate(goItem.Obj);
                    }
                    HTLogger.Debug("缓存中已存在，无需同步加载 GameObject，Path：{0}", goItem.Path);
                }
            }
            else
            {
                goItem = mGoItemPool.Spawn(true);
                goItem.Path = path;
                HTLogger.Debug("同步加载 GameObject，Path：{0}", goItem.Path);
                goItem.Obj = ResLoader.Instance.LoadSync<GameObject>(path);
                goItem.GO = GameObject.Instantiate(goItem.Obj);
                mGoItemCache.Add(path, goItem);
                mGoCache.Add(goItem.GO, goItem);
            }
            return goItem.GO;
        }

        /// <summary>
        /// 异步加载 GameObject
        /// </summary>
        /// <param name="path">加载路径</param>
        /// <param name="onLoaded">完成回调</param>
        public void LoadAsync(string path, Action<GoItem> onLoaded)
        {
            GoItem goItem = null;
            if (mGoItemCache.TryGetValue(path, out goItem))
            {
                if (System.Object.ReferenceEquals(goItem.Obj, null))
                {
                    ResLoader.Instance.LoadAsync(path, resItem =>
                     {
                         goItem.Obj = resItem.Obj as GameObject;
                         HTLogger.Debug("异步加载 GameObject 完成，Path：{0}", goItem.Path);
                         goItem.GO = GameObject.Instantiate(goItem.Obj);
                         onLoaded?.Invoke(goItem);
                     });
                }
                else
                {
                    if (System.Object.ReferenceEquals(goItem.GO, null))
                    {
                        goItem.GO = GameObject.Instantiate(goItem.Obj);
                    }
                    HTLogger.Debug("缓存中已存在，无需异步加载 GameObject ，Path：{0}", goItem.Path);
                    onLoaded?.Invoke(goItem);
                }
            }
            else
            {
                goItem = mGoItemPool.Spawn(true);
                goItem.Path = path;
                ResLoader.Instance.LoadAsync(path, resItem =>
                {
                    goItem.Obj = resItem.Obj as GameObject;
                    HTLogger.Debug("异步加载 GameObject 完成，Path：{0}", goItem.Path);
                    goItem.GO = GameObject.Instantiate(goItem.Obj);
                    mGoItemCache.Add(path, goItem);
                    mGoCache.Add(goItem.GO, goItem);
                    onLoaded?.Invoke(goItem);
                });
            }
        }

        /// <summary>
        /// 卸载 GameObject
        /// </summary>
        /// <param name="go">待卸载的 GameObject</param>
        /// <param name="clearMemory">是否清除内存</param>
        /// <param name="setToRecycle">是否添加到回收节点</param>
        public void Release(GameObject go, bool clearMemory, bool setToRecycle)
        {
            HTLogger.Debug("开始卸载 GameObject：{0}", go.name);
            GoItem goItem = null;
            if (mGoCache.TryGetValue(go, out goItem))
            {
                if (clearMemory) //清除内存
                {
                    HTLogger.Debug("清除内存，Path：{0}", goItem.Path);
                    mGoItemCache.Remove(goItem.Path);
                    mGoCache.Remove(go);
                    goItem.GO = null;
                    goItem.Obj = null;
                    ResLoader.Instance.Release(goItem.Path, clearMemory);
                    goItem.Reset();
                    mGoItemPool.Recycle(goItem);
                }
                else //不清除内存
                {
                    HTLogger.Debug("不清除内存，Path：{0}", goItem.Path);
                    if (setToRecycle) //设置到回收节点
                    {
                        go.transform.SetParent(RecycleTrans);
                    }
                    else
                    {
                        go.SetActive(false);
                    }
                }
            }
        }
    }
}
